﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<fstream>	
#include<sstream>
#include<string>
#include"Date.h"
using namespace std;
void test1()
{
	//cin四个状态
	cout << cin.good() << endl;
	cout << cin.fail() << endl;
	cout << cin.eof() << endl;
	cout << cin.bad() << endl;
	int i = 0;
	// 输入一个字符或多个字符，cin读取失败，流状态被标记为failbit
	cin >> i;
	cout << i << endl;
	cout << cin.good() << endl;
	cout << cin.eof() << endl;
	cout << cin.bad() << endl;
	cout << cin.fail() << endl << endl;
	//当输入失败的时候cin也就失效了，无法接着进行输入
	//cin.clear();
	//即使clear了也只是把输入从缓冲区中指出，并不影响流的状态，
	// 再次读入也会失败
	if (cin.fail())
	{
		// clear可以恢复流状态位goodbit
		cin.clear();
		// 我们还要把缓冲区中的多个字符都读出来，读到数字停下来，
		// 否则再去cin >> i还是会失败
		char ch = cin.peek();
		while (!(ch >= '0' && ch <= '9'))
		{
			ch = cin.get();
			cout << ch;
			ch = cin.peek();
		}
		cout << endl;
	}
	int x = 0;
	cin >> x;
	cout << x << endl;
}
void func(ostream& os)
{
	os << "hello world";
	os << "hello bit";
	// "hello world"和"hello bit"是否输出不确定
	system("pause");
	// 遇到endl	，"hello world"	和"hello bit"⼀定刷新缓冲区输出了
		//os << endl;
		 //os << flush;
		 //int i;
		 //cin >> i;
	os << "hello cat";
	// "hello cat"是否输出不确定
		system("pause");
}
void test2()
{
	// 在io需求⽐较⾼的地⽅，如部分⼤量输⼊的竞赛题中，
	// 加上以下⼏⾏代码可以提⾼	C++IO效率
	// 并且建议⽤'\n'替代endl，因为endl会刷新缓冲区
	// 关闭标准	C++流是否与标准C流在每次输⼊输出操作后同步。
		ios_base::sync_with_stdio(false);
	// 关闭同步后，以下程序可能顺序为b a c
		std::cout << "a\n";
		std::printf("b\n");
		std::cout << "c\n";
		// 解绑cin和cout关联绑定的其他流
		cin.tie(nullptr);
		cout.tie(nullptr);
}
void test3()
{
	int i;
	cin >> i;
	//cin不与任何流绑定
	cin.tie(nullptr);

}
////test1();
	//// 正确创建文件输出流对象
	//ofstream ofs("test.txt");

	//
	//// unitbuf设置后，	ofs	每次写都直接刷新
	//// ofs << unitbuf;
	//// cin绑定到ofs，cin进⾏读时，会刷新ofs的缓冲区
	//// cin.tie(&ofs);
	//// 将文件流传递给函数
	//func(ofs);

	//// 关闭文件流
	////ofs.close();
	/*int n = 0;
	cout << "请输入数字>";
	cin >> n;*/
void test4()
{
	int i = 0, j = 1;
	// 持续的输入，要结束需要输入Ctrl + Z换⾏，
	// Ctrl + Z用于告诉程序输入已经完成，类似于在文件末尾添加⼀个标记。

	// istream& operator>>(int i),>>算符重载的返回值是istream对象，
	// istream对象可以调用operator bool转换为bool值
	 // 本质在底层是将cin的eofbit和failbit标志位设置了，
	 // cin调用operator bool函数语法逻辑上实现转换为bool值
	while (cin >> i >> j)
	{
		cout << i << ":" << j << endl;
	}
	cout << cin.good() << endl;
	cout << cin.eof() << endl;
	cout << cin.bad() << endl;
	cout << cin.fail() << endl << endl;
	// 流⼀旦发⽣错误就不能再⽤了，清理重置⼀下再能使⽤

	cin.clear();
	string s;
	while (cin >> s)
	{
		cout << s << endl;
	}
}
void test5()
{
	ofstream ofs("tstt.txt");
	// 字符和字符串的写
	//put 是面向字符的类型安全操作，write 是面向字节的原始内存操作。
	/*ofs.put('x');
	ofs.write("hello\nworld", 11);*/
	//// 使⽤<<进⾏写
	//ofs << "22222222" << endl;
	int x = 111;
	double y = 1.11;
	ofs << x << endl;
	ofs << y << endl;
	ofs.close();
	//// app和ate都是尾部追加，
	// 不同的是app不能移动⽂件指针，永远是在⽂件尾写
	//ate可以移动⽂件指针，写到其他位置

	ofs.open("tstt.txt", ios_base::out | ios_base::app);
	ofs << "1111111" << endl;
	ofs.seekp(0, ios_base::beg);
	ofs << x << " " << y << endl;
	ofs.close();
	ofs.open("tstt.txt", ios_base::out | ios_base::ate);
	ofs << "1111111" << endl;
	ofs.seekp(0, ios_base::beg);
	ofs << x << " " << y << endl;
	ofs.close();

	// out和out | trunc都会先把数据清掉，再写数据（官⽅⽂档也明确是这样写的）
	// https://en.cppreference.com/w/cpp/io/basic_filebuf/open
	// 那么	trunc存在的意义是什么呢？
	//out | trunc更明确的表达了⽂件中有内容时要清除掉内	容
	//对于代码维护者和阅读者来说能清晰地理解这个⾏为，在⼀些复杂的⽂件系统环境或不同的
	// C++⽂件流实现库中, out⾏为不完全等同于截断内容的情况(虽然当前主流实现基本⼀致),
	// out|trunc更明确的表要清除内容的⾏为
	ofs.open("test.txt", ios_base::out);
	//ofs.open("test.txt", ios_base::out | ios_base::trunc);
	ofs << "xxxx";
	ofs.close();
}
void test6()
{
	// 实现⼀个图⽚⽂件的复制，需要⽤⼆进制⽅式打开读写，第⼀个参数可以给⽂件的绝对路径

	ifstream ifs("C:\\Users\\15699\\Pictures\\P站\\97512055_p0_master1200.jpg",
	ios_base::in | ios_base::binary);
	ofstream ofs("C:\\Users\\15699\\Pictures\\P站\\97512055_p0_master1200.jpg",
		ios_base::out | ios_base::binary);
	int n = 0;
	while (ifs && ofs)
	{
		char ch = ifs.get();
		ofs << ch;
		++n;
	}
	cout << n << endl;
}

void test7()
{
	writeBin();
	readBin();
	writeText();
	readText();
}
void test8()
{
	/*int i = 123;
	Date d = { 2025, 4, 10 };
	ostringstream oss;
	oss << i << endl;
	oss << d << endl;
	string s = oss.str();
	cout << s << endl;*/
	//stringstream iss(s);
	//stringstream iss;
	//iss.str("100 2025 9 9");
	/*istringstream iss("100 2025 9 9");
	int j;
	Date x;
	iss >> j >> x;
	cout << j << endl;
	cout << x << endl;*/
	int a = 1234;
	int b = 5678;
	string str;
	// 将⼀个整形变量转化为字符串，存储到string类对象中

	stringstream ss;
	ss << a << " " << b;
	ss >> str;
	cout << str << endl;
	cout << ss.fail() << endl;
	cout << ss.bad() << endl;
	// 注意多次转换时，必须使⽤clear将上次转换状态清空掉

	// stringstreams在转换结尾时(即最后⼀个转换后),
	// 会将其内部状态设置为badbit和	failbit
		// 	因此下⼀次转换是必须调⽤clear()将状态重置为goodbit才可以转换
	 // 但是clear()	不会将stringstreams底层字符串清空掉, 
	 // str给⼀个空串可以清掉底层的字符串
	ss.clear();
	ss.str("");
	double dd = 12.34;
	ss << dd;
	ss >> str;
	cout << str << endl;
}
class DATE
{
	friend ostream& operator << (ostream& out, const DATE& d);
	friend istream& operator >> (istream& in, DATE& d);
public:
	DATE(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
	}
private:
	int _year;
	int _month;
	int _day;
};
istream& operator >> (istream& in, DATE& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}
ostream& operator << (ostream& out, const DATE& d)
{
	out << d._year << " " << d._month << " " << d._day << endl;
	return out;
}
struct ChatInfo
{
	string _name; // 名字

	int _id;
	// id
	Date _date;   // 时间

	string _msg;  // 聊天信息

};
void test9()
{
	// 结构信息序列化为字符串

	ChatInfo winfo = { "张三", 135246, { 2022, 4, 10 }, "晚上一起看电影吧" };
	ostringstream oss;
	oss << winfo._name << " " << winfo._id << " " << winfo._date
		<< " " <<winfo._msg;
	string str = oss.str();
	cout << str << endl << endl;
	// 我们通过⽹络这个字符串发送给对象，实际开发中，信息相对更复杂，
	//⼀般会选⽤Json、	xml等⽅式进⾏更好的⽀持
	// 	字符串解析成结构信息
	ChatInfo rInfo;
	istringstream iss(str);
	iss >> rInfo._name >> rInfo._id >> rInfo._date >> rInfo._msg;
	cout << "-------------------------------------------------------" << endl;
	cout << "姓名：" << rInfo._name << "(" << rInfo._id << ") ";
	cout << rInfo._date << endl;
	cout << rInfo._name << ":>" << rInfo._msg << endl;
	cout << "-------------------------------------------------------" << endl;
}
int main()
{
	//test5();
	//test6();
	test7();
	//test8();
	//test9();
	return 0;
}